# Front End.
def render(templateString, **values):
    from django.template import Template, Context
    return Template(templateString).render(Context(values))

from xml.sax import make_parser
from xml.sax.handler import ContentHandler, ErrorHandler, property_lexical_handler
from xml.sax.xmlreader import InputSource

try: from cStringIO import StringIO
except ImportError: from StringIO import StringIO

def ParseString(source, handler):
    parser = make_parser()
    parser.setContentHandler(handler)
    parser.setErrorHandler(handler)
    parser.setProperty(property_lexical_handler, handler)

    inpsrc = InputSource()
    inpsrc.setByteStream(StringIO(source))
    parser.parse(inpsrc)

TAB = '  '
class XMLPrettifier(object, ContentHandler, ErrorHandler):
    # Lexical Handler
    comment = startCDATA = endCDATA = endDTD = None
    def startDTD(self, name, publicId, systemId):
        args = (name, publicId, systemId)
        self << '<!DOCTYPE %s>\n' % ' '.join(map(str, filter(None, args)))

    # ContentHandler
    def startElement(self, name, attrs):
        self.startElementNS(name, '', attrs)
    def endElement(self, name):
        self.endElementNS(name, '')

    def startElementNS(self, name, qname, attrs):
        self.flushCharacters()
        attrs = ' '.join('%s="%s"' % nv for nv in attrs.items())
        self << '<%s%s%s>\n' % (name, attrs and ' ' or '', attrs)
        self += 1
    def endElementNS(self, name, qname):
        self.flushCharacters()
        self -= 1
        self << '</%s>\n' % name

    def characters(self, content):
        self.addCharacters(content)
    def processingInstruction(self, target, data):
        self << '<?%s %s?>\n' % (target, data)

    # ErrorHandler:
    def handleError(self, exception):
        linenr = exception.getLineNumber()
        column = exception.getColumnNumber()

        lines = self.source.split('\n')
        line = lines[linenr - 1]

        print 'Fatal error parsing line %d, column %d:\n%s\n%s^' % \
              (linenr, column, line, ' ' * (column - 1))

    error = warning = fatalError = handleError

    def __new__(self, *args, **kwd):
        o = object.__new__(self)
        o.__init__(*args, **kwd)
        return str(o)

    def __init__(self, source, destbuf = None, tab = TAB):
        self.source = source
        if destbuf is None:
            destbuf = StringIO()

        self.destbuf = destbuf
        self.contentbuf = ''

        self.indent = 0
        self.tab = tab

        ParseString(source, self)

    @property
    def indenttab(self):
        try: return self._indenttab
        except AttributeError:
            t = self._indenttab = self.tab * self.indent
            return t

    def resetindenttab(self):
        try: del self._indenttab
        except AttributeError: pass

    def __iadd__(self, value):
        self.resetindenttab()
        self.indent += int(value)
        return self
    def __isub__(self, value):
        self.resetindenttab()
        self.indent -= int(value)
        return self

    def __lshift__(self, value):
        self.destbuf.write(self.indenttab)
        self.destbuf.write(value)
        return self

    def addCharacters(self, content):
        self.contentbuf += content
    def flushCharacters(self):
        content = self.contentbuf
        self.contentbuf = ''

        # Normalize whitespace.
        for line in content.split('\n'):
            if line:
                self << ' '.join(line.split())
                self.destbuf.write('\n')

    def __str__(self):
        return self.destbuf.getvalue()

def prettify(html):
    return XMLPrettifier(html)
